﻿using System;
using System.Collections.Generic;
using DataTier;

namespace Ecopsy.DataTier
{
    public class TreeEntitySingle : EntitySingle
    {
        private TreeEntitySingle _ParentNode = null;

        public TreeEntitySingle()
            : base()
        {
            _ChildNodes.OnAddChild += new AddChild(ChildNodes_OnAddChild);
            _ChildNodes._Owner = this;
        }
        
        private TreeEntityList _ChildNodes = new TreeEntityList();
        public virtual  TreeEntityList ChildNodes {get{return _ChildNodes;} }

        public virtual TreeEntitySingle ParentNode { get { return _ParentNode; } set { _ParentNode = value; } }

        /// <summary>
        /// Рекурсивный поиск потомка в дереве
        /// </summary>
        /// <param name="ID"></param>
        /// <returns></returns>
        public TreeEntitySingle Find(string ID)
        {             
            TreeEntitySingle r= FindNextItem (this, ID);
            this.ChildNodes.Reset();
            return r;
        }

        [EntityNonSerialized]
        public TreeEntitySingle First
        {get 
            {       
                return FindNextItem(this,"FIRST");
            }
        }

        private TreeEntitySingle FindNextItem(TreeEntitySingle Parent, string ID)
        {
            if (ID == "FIRST")
            {                
                if (null == Parent.ParentNode) return Parent;
                if (Parent.ParentNode.ID == DataTierConstants.qProxyId)
                                return Parent;
                    
            }


            if (ID == Parent.ID) return Parent;
            Parent.ChildNodes.Reset();
            foreach (object Item in Parent.ChildNodes)
            {
                if (!(Item is TreeEntitySingle)) continue;
                TreeEntitySingle obj = FindNextItem((TreeEntitySingle)Item, ID);
                if (null != obj) return obj;
            }
            Parent.ChildNodes.Reset();
            return null;
        }

        private void ChildNodes_OnAddChild(object obj)
        {
            if (obj is TreeEntitySingle) ((TreeEntitySingle)obj).ParentNode = this;
        }

        public virtual HashSet<T> ToHashSet<T>(IEqualityComparer<T> cmp)
        {
            return ChildNodes.ToHashSet(cmp);
        }


        public virtual HashSet<EntitySingle> ToHashSet()
        {
            return ChildNodes.ToHashSet(); 
        }

        
        
     
    }

    public class TreeEntityList : EntityList
    {

        public event AddChild OnAddChild;

        public TreeEntitySingle _Owner = null;
        /// <summary>
        /// Возвращает ID владельца OwnerId
        /// </summary>
        public string ID{ get 
        {
            if (null == _Owner) return string.Empty;
            return _Owner.ID; 
        } 
        }
        
        [EntityNonSerialized] 
        public TreeEntitySingle Def_Parent { get { return _Owner; } set { _Owner = value; } }

        public override void Add(object  Value)
        {
            base.Add(Value);
            if ((Value is TreeEntitySingle))
            {
                if (OnAddChild != null)
                    OnAddChild(Value);
            }
        }
        public override void Add(System.Collections.ICollection obj)
        {
            base.Add(obj);
        }


        public override HashSet<EntitySingle> ToHashSet()
        {
            EntityList.EntitySingleHasComparer cm = new EntitySingleHasComparer();
            return ToHashSet(cm);
        }
        
        /// <summary>
        /// Рекурсивно ToHashSet для каждого TreeEntitySingle
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cmp"></param>
        /// <returns></returns>
        public override HashSet<T> ToHashSet<T>(IEqualityComparer<T> cmp)
        {

            HashSet<T> res = new HashSet<T>(cmp);
            HashSet<T> hs=null;
            this.Reset();
            foreach (T item in this)
            {
                if ((item as TreeEntitySingle).ChildNodes.Count > 0)
                {
                    hs = (item as TreeEntitySingle).ToHashSet<T>(cmp);
                    foreach (T i in hs)
                                    res.Add(i);
                }
                else
                    res.Add(item);
                       
                    
                
            }
            return res;
            
        }
    }

    public static class TreeEntityExt
    {
        public static List<TreeEntitySingle> ToList(this TreeEntitySingle TreeNode)
        {
            Func<TreeEntitySingle, List<TreeEntitySingle>, List<TreeEntitySingle>> f = delegate(TreeEntitySingle nd, List<TreeEntitySingle> coll)
            {
                coll.Add(nd);
                return coll;
            };
            List<TreeEntitySingle> Collection = new List<TreeEntitySingle>();
            FindChild(TreeNode, Collection, f);
            return Collection;
        }

        private static void FindChild(TreeEntitySingle nd, List<TreeEntitySingle> Collection, Func<TreeEntitySingle, List<TreeEntitySingle>, List<TreeEntitySingle>> f)
        {
            Collection = f(nd, Collection);
            foreach (TreeEntitySingle item in nd.ChildNodes) FindChild(item, Collection, f);

        }

    }

 
}

